#!/usr/sbin/rsct/perl5/bin/perl 
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# "@(#)98   1.32   src/rsct/registry/cli/bin/mksrtbl.perl, srcli, rsct_rpyxh, rpyxht1f3 2/22/01 16:25:28"
######################################################################
#                                                                    #
# Module: mksrtbl                                                    #
#                                                                    #
# Purpose:                                                           #
#   mksrtbl - Makes (creates) a new System Registry table.           #
#                                                                    #
# Syntax:                                                            #
#   To create a table using data entered on the command line:        #
#       mksrtbl [-h][-m Mode][-TV] Table col=Name type=Data_type     #
#               [qual=Qualifier def=Default_value] ...               #
#                                                                    #
#   To create a table using data predefined in an input file:        #
#       mksrtbl [-h][-m Mode][-TV] -f Table_definition_file Table    #
#                                                                    #
# NOTE: the -m flag is not fully supported. The underlying Security  #
#   stucture is not in place at this time (07/01/1999)               #
#                                                                    #
# Flags:                                                             #
#   -h Help. Writes this command's usage statement to stdout.        #
#   -f Table_definition_file                                         #
#       File input. Instead of command line data, use an input file  #
#       containing names of tables to be altered including           #
#       descriptions of columns to be added to the new table. Format #
#       is listed under Description.                                 #
#   -m Mode Defines the permissions for the newly created table.     #
#       To be defined when security is further along.                #
#   -T Trace. Writes this command's trace messages to stderr.        #
#   -V Verbose. Writes this command's verbose messages to stderr.    #
#                                                                    #
# Operands:                                                          #
#   Table   The table you wish to add columns to. The Table can be a #
#           relative or absolute path name.                          #
#   col=Name The name of a column to be made in the new table, must  #
#           be a valid alphanumeric string. Recommend column names   #
#           follow the OO naming styles of WordWord (no underbars.)  #
#           example: NodeNumber, not node_number.                    #
#   type=Data_type The data type to be stored in a given column.     #
#           Valid types are listed under Description.                #
#   qual=Qualifier Required for Primary Key (PK), otherwise Optional #
#           Denotes the type of column. Valid qualifiers are listed  #
#           under Description.                                       #
#   def=Default_value Optional. Default value for the column. This   #
#           value is treated by the System Registry to be of the data#
#           type given for the column.                               #
#                                                                    #
# Description:                                                       #
#   The mksrtbl command allows you to make a new System Registry     #
#   table specified by the Table operand. Table names must be unique #
#   to the local directory. A table is defined using column metadata #
#   (definitions.) Column definitions can be supplied either on the  #
#   command line or via an input definition file. They consist of    #
#   sets of information: column name, data type, qualifier and       #
#   default value.                                                   #
#   Column names must be unique to a table. Valid column names start #
#   with a letter and can contain alphanumeric characters and        #
#   underscores. It is suggested that OO naming conventions be       #
#   followed, however. (ie, using EthernetAdapter instead of         #
#   Ethernet_Adapter.) The table will automatically have             #
#   a system-generated column named RowChangeCounter. This name can  #
#   not be used for any other column.                                #
#                                                                    #
#   The entire path name for a table, including the name can not     #
#   exceed 254 characters in length. Any valid AIX file name can be  #
#   used for a table name. Table names must be unique to a directory.#
#   Tables and directories in the same parent directory can not have #
#   the same name.                                                   #
#                                                                    #
#   A single primary key is required to be included in the column    #
#   definitions for the table. Only one primary key column is allowed#
#   per table. Keys can be any of the valid data types.              #
#                                                                    #
#   The table is automatically assigned the permissions of it's      #
#   parent directory.                                                #
#                                                                    #
#   Valid qualifiers are: pk|PK - Primary key, st|ST Standard column #
#                                                                    #
#   Valid data types are: i|I = 32 bit int, ui|UI = unsigned 32 bit  #
#   int, l|L 64 bit int (long), ul|UL unsigned 64 bit int,           #
#   f|F float, d|D double, s|S string, rh|RH resource handle,        #
#   b|B binary.                                                      #
#                                                                    #
#   Qualifiers and data types can be entered in upper or lower case. #
#                                                                    #
#   Resource handles are entered as hexadecimal, using the format    #
#       (including quotes):                                          #
#       "0x#### 0x#### 0x######## 0x######## 0x######## 0x########"  #
#   where '########' is a hexadecimal number. If more than 5         #
#   numbers are given, only the first 5 will be used. If less than   #
#   5 are given, 0x00000000 will be placed in the missing places.    #
#                                                                    #
#   Binary data is entered as hexadecimal, using the format          #
#       (including quotes):                                          #
#       "0x######## 0x######## 0x######## ...."    -OR-              #
#       "0x################...."                                     #
#   where '########' is a hexadecimal number. The length of the      #
#   hexadecimal string is not significant (each number could be      #
#   more or less than 8 digits). Values are stored as                #
#   given in the System Registry (the leading 0x is stripped off     #
#   for storage.)                                                    #
#                                                                    #
#   Long and unsigned long (64 bit) are expected in decimal format.  #
#   It is up to the caller to make sure the column value matches the #
#   data type.                                                       #
#                                                                    #
#   Strings with spaces need to be enclosed in quotes.               #
#                                                                    #
#   For more information on entering the data types, please refer to #
#   the man page for mksrcol.                                        #
#                                                                    #
#   Input file format:                                               #
#                                                                    #
#   Column definition data (metadata) for a new table goes in a flat #
#   text file in a stanza headed by the keyword 'TableDefinition':   #
#       TableDefinition::                                            #
#       column 1:                                                    #
#           col  = <name>                                            #
#           type = <data_type>                                       #
#           qual = <qualifier>                                       #
#           def  = <default_value>                                   #
#       column 2:                                                    #
#           col  = <name>                                            #
#           type = <data_type>                                       #
#           qual = <qualifier>                                       #
#           sd_defn = <name>_SDDefinition                            #
#           def  = <default_value>                                   #
#           ...                                                      #
#                                                                    #
#       <name>_SDDefinition::                                        #
#       element 0:                                                   #
#           name = <element name>                                    #
#           type = <data_type>                                       #
#           def  = <default_value>                                   #
#       element 1:                                                   #
#           ...                                                      #
#                                                                    #
#   The tab at the beginning of each line is provided here for       #
#   readability but is not necessary in the input file. Only one     #
#   table definition can be contained in the input file. If more than#
#   one table definitions exists in the input file, only the first   #
#   will be read in.                                                 #
#                                                                    #
#   The <name>_SDDefinition stanza declares a structured data        #
#   definition for a column using structured data or structured      #
#   data arrays.                                                     #
#                                                                    #
#   If a ColumnDefinition stanza contains a 'sd_defn=' line, then    #
#   it will be assumed there is a corresponding SDDefinition stanza  #
#   in the input file.                                               #
#                                                                    #
#   Default values given in SDDefinition stanzas are overridden by   #
#   values given in the TableDefinition stanza.                      #
#                                                                    #
# Exit Values:                                                       #
#   0  SR_CLI_SUCCESS        Command completed successfully.         #
#   1  SR_CLI_REGISTRY_ERROR Command terminated due to an underlying #
#                            System Registry error.                  #
#   2  SR_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  SR_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   4  SR_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   5  SR_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an existing      #
#                            table to be created.                    #
#                                                                    #
# Examples:                                                          #
#  Note: In these examples, the directories mentioned are assumed    #
#  to already have been created using the mksrdir command.           #
#                                                                    #
#   mksrtbl -f newtable /testing/table1                              #
#   - adds 'table1' to the directory testing using column data in    #
#   the input file 'newtable' from the current directory.            #
#                                                                    #
#   mksrtbl /temp/Table3 column_name=c1 data_type=I qualifier=PK     #
#       default_value=32 column_name=c2 data_type=S qualifier=ST     #
#       default_value="Betty" column_name=c3 data_type=I             #
#       qualifier = ST default_value=6457                            #
#   - adds 'Table3' to directory /temp using 3 column definitions    #
#   given on the command line.                                       #
#                                                                    #
#   mksrtbl /samples/Table4 col=c1 type=I qual=PK col=c2 type=RH     #
#       def="0xffffffff 0x12345678 0x00000000 0x00000000 0x00000000" #
#       col=c3 type=L def=9233456798234 col=b4 type=B def="0xffff"   #
#   - adds 'Table4' to directory /samples using RH and L data types  #
#                                                                    #
#   mksrtbl /temp/table1 col=key type=I qual=PK                      #
#    - minimal method of adding a table, defining the primary key    #
#    only, and using short forms of the keywords.                    #
#                                                                    #
#--------------------------------------------------------------------#
#                                                                    #
# Inputs:                                                            #
#   user input from command line or file                             #
#                                                                    #
# Outputs:                                                           #
#   stdout - progress and/or Verbose messages                        #
#   stderr - error messages                                          #
#                                                                    #
# External Ref:                                                      #
#   Commands: $LSMSG                                                 #
#   Extensions:  CT::SR.pm CT::SRrc.pm                               #
#   Perl library routines: Getopts::Std                              #
#   CLI library routines:                                            #
#           SR_cli_column_utils - make_col_struct grab_file_data     #
#                                 grab_cmdline_data                  #
#           SR_cli_utils - init_session clean_session  error_exit    #
#                      printCEMsg set_session_variables              #
#           SR_cli_rc - CLI return codes                             #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000929 HGJ 38317: Initial delivery.                              #
#                                                                    #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A: Parse command line - get table name and input file              #
# B: Initialise session with registry, including changing the        #
#    current directory if a relative path name is given (use value   #
#    given in CT_SR_HOME.)                                           #
# C: Parse input file, if necessary. Create column data to be fed    #
#    into CT::SR::create_table.                                      #
# D: Call CT::SR::create_table to create table if possible           #
# E: Clean up session table and tree                                 #
#                                                                    #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;

use CT::CT;
use CT_cli_utils qw(printIMsg
                    printEMsg
);

use CT::SRrc;
use CT::SR;
use SR_cli_column_utils qw( grab_file_data 
                            grab_cmdline_data
                            make_col_struct
);
use SR_cli_utils qw(init_session 
                    printCEMsg
                    $DEFAULT_GLOBAL_MOUNT_POINT
                    set_session_variables       
                    clean_session
                    error_exit
);
use SR_cli_rc qw(:return_codes);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
# Constants
$TRUE           = 1;
$FALSE          = 0;

# Globals used to map variables captured from getopts
$Trace          = $FALSE;               # See -T flag
$Verbose        = $FALSE;               # See -V flag

$Opt_File_Input = $FALSE;               # See -f flag

# Messaging Variables
$PROGNAME       = "mksrtbl";            # Program Name for messages
$MSGCAT         = "srcli.cat";          # msg catalogue for this cmd
$CTDIR          = "/usr/sbin/rsct";     # Cluster directory path
$CTBINDIR       = "$CTDIR/bin";         # Cluster Bin directory path
$LSMSG          = "$CTBINDIR/ctdspmsg"; # Display message routine
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # Msg maps used by $LSMSG

%Cleanup = ();                          # Hash of items to cleanup
                                        # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $Tree_handle    = "";
# For use in extension calls
my $New_table      = CT::SR::table_handle_t->new;
my $Table_name     = "";
my $Table          = "";
my $filename       = "";
my $Set_work_dir   = $FALSE;
my $Column_data    = "";

my $rc             = 0;                 # assume good return code

my $Mount_point    = $DEFAULT_GLOBAL_MOUNT_POINT;


#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
# TODO: Many verbose statements in this code will eventually by
# Trace statements when the facility is available as a Perl CLI
# (feature 48401)
# TODO: security on access to the table can not be further defined
# until after a security design has been implemented for the SR.
# ( feature 48402 ) Until then, the table is opened with the
# minimum security necessary to complete the command.


# Parse the command line, exit if there are errors
($rc, $Table_name, $filename) = parse_cmd_line();  
($rc == 0) || error_exit($rc);


# Set up the registry session
($Set_work_dir, $Table) = set_session_variables($Table_name);
($rc,$Tree_handle) = init_session($Set_work_dir);
($rc == 0) || error_exit($rc);

# Add tree handle to cleanup hash
$Cleanup{Session} = $Tree_handle;


# Pull in column data and put into the correct structure for
# passing to the extension
if ($Opt_File_Input) {
    # Pull in the data from an input file
    # Create the column structure from the input data
    ($rc, $Column_data) = grab_file_data($filename, "TableDefinition"); 
} 
else {  
    # Pull in the data from command line
    # Create the column structure directly from @ARGV data
    ($rc, $Column_data) = grab_cmdline_data(@ARGV); 
}

# Check error code and quit if necessary
($rc == 0) || error_exit($rc);


# Create the column structure
($rc, @Column_ptr) = make_col_struct($Column_data); 
($rc == 0) || error_exit($rc);

               
# Make the extension call to CT::SR::create_table
$Verbose && 
    printIMsg("IMsgmksrtblMakingTable", $Table_name, $Table ); 

$Trace && print STDERR "Calling CT::SR::create_table\n";
$rc = CT::SR::create_table($Tree_handle, $Table, \@Column_ptr, 
                        $New_table);
$Trace && print STDERR "CT::SR::create_table return code: $rc\n";
$rc = error_check("sr_create_table", $rc, $Table_name);
($rc == 0) || error_exit($rc);

$rc = clean_session($Tree_handle, $Mount_point, $New_table);

exit $rc;

#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line:                                                    #
#   Uses getopts() to grab flags on the command line, including an   #
#   input file name if the '-f' flag is used.                        #
#                                                                    #
# Return values:                                                     #
#   $table_name - table name to be added                             #
#                                                                    #
# Global variables modified:                                         #
#   $Opt_File_Input    output   True (-f) use input file.   
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my $file_name = ""; 
my $local_rc = 0;
my $filename = "";
my %opts = ();

if (getopts('f:hm:TV', \%opts) == 0) {  # parse input flags
    printCEMsg("EMsgSRcliInvalidFlag");
    print_usage();
    return SR_CLI_BAD_FLAG;             # error parsing command line
}     
              
if (defined $opts{h}) {                 # print usage and exit
    print_usage();
    exit(0);                            # success but quit
}

# Set Trace flag if requested    
if (defined $opts{T}) {
    $Trace = $TRUE;
}

# Set Verbose flag if requested    
if (defined $opts{V}) {
    $Verbose = $TRUE;
}

my $table_name = shift @ARGV;
if ((!$table_name) || ($table_name =~ /=/)) {
    printCEMsg("EMsgSRcliNoTableName");
    print_usage();
    return SR_CLI_BAD_OPERAND;  
}

if (defined $opts{f}) {
    $Opt_File_Input = $TRUE;
    $filename = $opts{f};            # -f <input_file_name>  
}
elsif ($#ARGV < 1) {
    # Make sure if no -f flag that we have at least the key=value,
    # and one more column=value specified.
    printCEMsg("EMsgSRcliNoColumnData");
    print_usage();
    return SR_CLI_BAD_OPERAND;
}

# TODO: This option will be fully supported after security is better
# defined (feature 48402)
if (defined $opts{m}) {
    print "-m Option not fully supported at this time. Table will be created with permissions of parent directory.\n";
}

return ($local_rc, $table_name, $filename);
} # end parse_cmd_line


#--------------------------------------------------------------------#
# error_check:                                                       #
#   Checks the return code from the SR function.  If an error is     #
#   detected appropriate error messages will be displayed and        #
#   SR CLI return code set.                                          #
#                                                                    #
# Parameters:                                                        #
#   $sr_function  - Name of the SR function that was called and      #
#                   whose error code we are checking.                #
#   $sr_rc        - SR function return code.                         #
#   $table_name   - Name of the table trying to create.              #
#                                                                    #
# Return values:                                                     #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($sr_function, $sr_rc, $table_name) = @_;
my $rc = 0;

if ($sr_rc!=0) {
    if ($sr_rc == SR_NO_PERMISSION) {
        printEMsg("EMsgmksrtblNoPermission", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_DIRECTORY) {
        printCEMsg("EMsgSRcliNoDirectory", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_TABLE_EXISTS) {
        printEMsg("EMsgmksrtblTableExists", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_KEY_EXPECTED) {
        printEMsg("EMsgmksrtblKeyExpected", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_DUPLICATE_KEY) {
        printEMsg("EMsgmksrtblDuplicateKey");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_DUPLICATE_COLUMN) {
        printEMsg("EMsgmksrtblDuplicateColumn");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_INVALID_COLUMN) {
        printCEMsg("EMsgSRcliInvalidColumnData", $sr_function, $sr_rc);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_IN_TRANSACTION) {
        printCEMsg("EMsgSRcliInTransaction");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_CONNECTION_LOST) {
        printCEMsg("EMsgSRcliConnectionLost");
        $rc = SR_CLI_REGISTRY_ERROR;
    }
    else {
        printEMsg("EMsgmksrtblErrorMakingTbl", $table_name);
        printCEMsg("EMsgSRcliSRCommandFailure", $sr_function, $sr_rc);
        $rc = SR_CLI_REGISTRY_ERROR;
    }
}

return ($rc);
}   # end error_check


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgmksrtblUsage");
}   # end print_usage


#--------------------------------------------------------------------#
# End File                                                           #
#--------------------------------------------------------------------#
